using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.Globalization;
using System.Threading;
using System.Windows.Forms;
using System.Drawing;
using System.Text;

using Styx;
using Styx.CommonBot;
using Styx.CommonBot.Routines;
using Styx.Helpers;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using Styx.Common.Helpers;
using Styx.Pathing;

using CommonBehaviors.Actions;

using Singular.Dynamics;
using Singular.Helpers;
using Singular.Managers;
using Singular.Settings;

using Action = Styx.TreeSharp.Action;
//
using Rest = Singular.Helpers.Rest;
//
using LocationRetriever = Singular.Helpers.LocationRetriever;
using yoyo;

namespace Armed
{
    public class Routine : CombatRoutine
    {
        /// <summary>
        /// The name of this CombatRoutine
        /// </summary>
        /// <value>
        /// The name.
        /// </value>
        public override string Name { get { return "Armed2.0"; } }


        /// <summary>
        /// The <see cref="T:Styx.WoWClass"/> to be used with this routine
        /// </summary>
        /// <value>
        /// The class.
        /// </value>
        public override WoWClass Class { get { return WoWClass.Warrior; } }


        private Composite _combat, _buffs;

        public override bool WantButton { get { return true; } }

        public override Composite CombatBehavior { get { return _combat; } }
        public override Composite PreCombatBuffBehavior { get { return _buffs; } }
        public override Composite CombatBuffBehavior { get { return _buffs; } }

        public override void OnButtonPress()
        {
            //Logger.Write(Colors.Yellow, "Config opened!");
            yoyo.yoyoForm1 myConfig = new yoyo.yoyoForm1();
            myConfig.ShowDialog();
        }

		private bool IsTargetBoss()
        {
            if (StyxWoW.Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.WorldBoss ||
               (StyxWoW.Me.CurrentTarget.Level >= 90 && StyxWoW.Me.CurrentTarget.Elite && StyxWoW.Me.CurrentTarget.MaxHealth > 10000000))
                return true;

            else return false;
        }

        public override void Initialize()
        {
            _combat = CreateCombat();
            _buffs = CreateBuffs();
        }

		private int addCount()
        {
            int count = 0;
            foreach (WoWUnit u in ObjectManager.GetObjectsOfType<WoWUnit>(true, true))
            {
                if (u.IsAlive
                    && StyxWoW.Me.CurrentTarget != null
                    && u.Guid != StyxWoW.Me.Guid
                    && !u.IsFriendly
                    && (u.IsHostile || u.IsNeutral)
                    && !u.IsCritter
                    && u.Location.Distance(StyxWoW.Me.Location) <= 10
                    && (u.IsTargetingMyPartyMember || u.IsTargetingMyRaidMember || u.IsTargetingMeOrPet || u.IsTargetingAnyMinion))
                {
                    count++;
                }
            }
            return count;
        }

		private int HSaddCount()
        {
            int count = 0;
            foreach (WoWUnit u in ObjectManager.GetObjectsOfType<WoWUnit>(true, true))
            {
                if (u.IsAlive
                    && StyxWoW.Me.CurrentTarget != null
                    && u.Guid != StyxWoW.Me.Guid
                    && !u.IsFriendly
                    && (u.IsHostile || u.IsNeutral)
                    && !u.IsCritter
                    && u.IsWithinMeleeRange
                    && (u.IsTargetingMyPartyMember || u.IsTargetingMyRaidMember || u.IsTargetingMeOrPet || u.IsTargetingAnyMinion))
                {
                    count++;
                }
            }
            return count;
        }
		
        Composite CreateBuffs()
        {
            return new PrioritySelector(
				Cast("Battle Shout", ret => !StyxWoW.Me.HasAura("Battle Shout") && !StyxWoW.Me.Mounted),
				new Decorator(ret =>
					!StyxWoW.Me.HasAura("Visions of Insanity") && !SpellManager.Spells["Crystal of Insanity"].Cooldown,
					new Action(abc =>
					{
						WoWItem item = StyxWoW.Me.BagItems.Find(ret => ret.Entry == 86569);
						if (item != null) item.Use(); 
					})
				)
			);
        }


        Composite CreateCombat()
        {
			return new Decorator ( ctz => !StyxWoW.Me.Mounted || !StyxWoW.Me.HasAura("Drink") || !StyxWoW.Me.HasAura("Food") || !StyxWoW.Me.HasAura("First Aid"),
			new PrioritySelector( 

				//Movement
				new Decorator ( ctt =>!yoyoSettings.myPrefs.DisableAllMovement && !StyxWoW.Me.CurrentTarget.IsWithinMeleeRange,				
				new Action(ret => 
				{ 
                        Navigator.MoveTo(StyxWoW.Me.CurrentTarget.Location);
				})),
				new Action(ret => 
				{ 
                    if (!yoyoSettings.myPrefs.DisableAllMovement && StyxWoW.Me.CurrentTarget.IsWithinMeleeRange && StyxWoW.Me.IsMoving)
                    {
                        WoWMovement.MoveStop();
						//return;
                    };
					return RunStatus.Failure;
				}),
				//Facing
				new Action(ret => 
				{ 
					if (!yoyoSettings.myPrefs.DisableAllFacement)
					{
						StyxWoW.Me.CurrentTarget.Face();
					};
					return RunStatus.Failure; 
				}),

                // Interrupt please.
                Cast("Pummel", ret => StyxWoW.Me.CurrentTarget.IsCasting && StyxWoW.Me.CurrentTarget.CanInterruptCurrentSpellCast),
                Cast("Disrupting Shout", ret => StyxWoW.Me.CurrentTarget.IsCasting && StyxWoW.Me.CurrentTarget.CanInterruptCurrentSpellCast && !SpellManager.CanCast("Pummel")),
                Cast("Storm Bolt", ret => StyxWoW.Me.CurrentTarget.IsCasting && StyxWoW.Me.CurrentTarget.CanInterruptCurrentSpellCast && !SpellManager.CanCast("Pummel")),
                Cast("Impending Victory", ret => StyxWoW.Me.HealthPercent <= 85 && StyxWoW.Me.HasAura("Victorious")),
                Cast("Victory Rush", ret => StyxWoW.Me.HealthPercent <= 85 && StyxWoW.Me.HasAura("Victorious")),

                Cast("Recklessness", ret => IsTargetBoss()), //StyxWoW.Me.CurrentTarget.MaxHealth > 3500000), // || addCount() > 4),
                Cast("Avatar", ret => IsTargetBoss()),
                Cast("Skull Banner", ret => IsTargetBoss() || addCount() > 5),
                Cast("Bloodbath", ret => IsTargetBoss() || StyxWoW.Me.CurrentTarget.IsPlayer || addCount() > 4),
                //Cast("Bloodbath", ret => StyxWoW.Me.CurrentTarget.IsBoss),
                Cast("Berserker Rage", ret => GetSpellCooldown("Colossus Smash").TotalSeconds < 1),

                Cast("Hamstring", ret => StyxWoW.Me.CurrentTarget.IsPlayer && !StyxWoW.Me.CurrentTarget.HasMyAura("Hamstring")),

                new Action(ret => { UseTrinkets(); return RunStatus.Failure; }),

                // Kee SS up if we've got more than 2 mobs to get to killing.
//                new Decorator(ret => UnfriendlyUnits.Count() >= 2,
//                    CreateAoe()),

				//AOE ================
                Cast("Dragon Roar", ret => addCount() > 2),
                Cast("Shockwave", ret => addCount() > 2),
                Cast("Bladestorm", ret => addCount() > 3),
                Cast("Whirlwind", ret => addCount() > 3 && !StyxWoW.Me.HasAura("Sweeping Strike")),
                Cast("Sweeping Strikes", ret => HSaddCount() > 1),
                //Cast("Cleave"),
				Cast("Thunder Clap", ret => addCount() > 2),
				// ===================
					
/*
                new Decorator(ret => StyxWoW.Me.CurrentTarget.HealthPercent <= 20,
                    CreateExecuteRange()),
                new Decorator(ret => StyxWoW.Me.CurrentTarget.HealthPercent > 20,
                    new PrioritySelector(
*/

                        // Only drop DC if we need to use HS for TFB. This lets us avoid breaking HS as a rage dump, when we don't want it to be one.
                        Cast("Colossus Smash", ret => !StyxWoW.Me.CurrentTarget.HasAura("Colossus Smash")),
                        Cast("Execute"),
                        Cast("Deadly Calm", ret => NeedTasteForBloodDump),
                        //Cast("Heroic Strike", ret => NeedHeroicStrikeDump),

                        Cast("Mortal Strike"),
                        Cast("Overpower"),


                        // Rage dump!
                        Cast("Slam", ret => (StyxWoW.Me.RagePercent >= 60 || StyxWoW.Me.CurrentTarget.HasAura("Colossus Smash")) && StyxWoW.Me.CurrentTarget.HealthPercent > 20),
                        //Cast("Heroic Strike", ret => (StyxWoW.Me.RagePercent >= 60 || StyxWoW.Me.CurrentTarget.HasAura("Colossus Smash")) && StyxWoW.Me.CurrentTarget.HealthPercent > 20),


                        Cast("Battle Shout"), //, ret => StyxWoW.Me.RagePercent < 30),
						Cast("Dragon Roar"),
                        Cast("Victory Rush"),
                        Cast("Heroic Throw"),


                        // Don't use this in execute range, unless we need the heal. Thanks!
                        Cast("Impending Victory")
                    //)
            )); 
        }
        Composite CreateAoe()
        {
            return new PrioritySelector(
                Cast("Dragon Roar"),
                Cast("Shockwave"),
                Cast("Bladestorm", ret=>UnfriendlyUnits.Count() >= 4),
                Cast("Whirlwind", ret=>UnfriendlyUnits.Count() >= 3),
                Cast("Sweeping Strikes"),
                //Cast("Cleave"),
				Cast("Thunder Clap")
                
                );
        }
        Composite CreateExecuteRange()
        {
            return new PrioritySelector(


                // Pop all our CDs. Get ready to truck the mob.
                Cast("Recklessness", ret => StyxWoW.Me.CurrentTarget.IsBoss()),
                Cast("Skull Banner", ret => StyxWoW.Me.CurrentTarget.IsBoss()),
                Cast("Avatar", ret => StyxWoW.Me.CurrentTarget.IsBoss()),
                Cast("Bloodbath", ret => StyxWoW.Me.CurrentTarget.IsBoss()),
                Cast("Berserker Rage"),


                Cast("Colossus Smash"),
                Cast("Execute"),
                Cast("Mortal Strike"),
                Cast("Overpower"),
                Cast("Storm Bolt"),
                Cast("Dragon Roar"),
                Cast("Slam"),
                Cast("Battle Shout")


                
                );
        }


        Composite HeroicLeap()
        {
            return new Decorator(ret=> StyxWoW.Me.CurrentTarget.HasAura("Colossus Smash") && SpellManager.CanCast("Heroic Leap"),
                new Action(ret=>
                    {
                        var tpos = StyxWoW.Me.CurrentTarget.Location;
                        var trot = StyxWoW.Me.CurrentTarget.Rotation;
                        var leapRight = WoWMathHelper.CalculatePointAtSide(tpos, trot, 5, true);
                        var leapLeft = WoWMathHelper.CalculatePointAtSide(tpos, trot, 5, true);


                        var myPos = StyxWoW.Me.Location;


                        var leftDist = leapLeft.Distance(myPos);
                        var rightDist = leapRight.Distance(myPos);


                        var leapPos = WoWMathHelper.CalculatePointBehind(tpos, trot, 8);


                        if (leftDist > rightDist && leftDist <= 40 && leftDist >= 8)
                            leapPos = leapLeft;
                        else if (rightDist > leftDist && rightDist <= 40 && rightDist >= 8)
                            leapPos = leapLeft;


                        SpellManager.Cast("Heroic Leap");
                        SpellManager.ClickRemoteLocation(leapPos);
                        StyxWoW.Me.CurrentTarget.Face();
                    }));
        }


        void UseTrinkets()
        {
            var firstTrinket = StyxWoW.Me.Inventory.Equipped.Trinket1;
            var secondTrinket = StyxWoW.Me.Inventory.Equipped.Trinket2;


            if(firstTrinket != null && CanUseEquippedItem(firstTrinket))
                firstTrinket.Use();


            if(secondTrinket != null && CanUseEquippedItem(secondTrinket))
                secondTrinket.Use();


        }
        private static bool CanUseEquippedItem(WoWItem item)
        {
            // Check for engineering tinkers!
            string itemSpell = Lua.GetReturnVal<string>("return GetItemSpell(" + item.Entry + ")", 0);
            if (string.IsNullOrEmpty(itemSpell))
                return false;


            return item.Usable && item.Cooldown <= 0;
        }


        IEnumerable<WoWUnit> UnfriendlyUnits
        {
            get { return ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(u => !u.IsDead && u.CanSelect && u.Attackable && !u.IsFriendly && u.IsWithinMeleeRange); }
        }


        bool NeedTasteForBloodDump
        {
            get
            {
                var tfb = StyxWoW.Me.GetAuraByName("Taste for Blood");
                if (tfb != null)
                {
                    // If we have more than 3 stacks, pop HS
                    if (tfb.StackCount >= 3)
                        return true;


                    // If it's about to drop, and we have at least 2 stacks, then pop HS.
                    // If we have 1 stack, then a slam is better used here.
                    if (tfb.TimeLeft.TotalSeconds < 1 && tfb.StackCount >= 2)
                        return true;
                }
                return false;
            }
        }


        bool NeedHeroicStrikeDump
        {
            get
            {
                // Flat out, drop HS if we need to.
                if (StyxWoW.Me.RagePercent >= 40)
                    return true;


                return NeedTasteForBloodDump;
            }
        }


        private delegate T Selection<out T>(object context);
        Composite Cast(string spell, Selection<bool> reqs = null)
        {
            return
                new Decorator(
                    ret => ((reqs != null && reqs(ret)) || (reqs == null)) && SpellManager.CanCast(spell),
                    new Action(ret => SpellManager.Cast(spell)));
        }


        public static TimeSpan GetSpellCooldown(string spell)
        {
            SpellFindResults results;
            if (SpellManager.FindSpell(spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Original.CooldownTimeLeft;
            }


            return TimeSpan.MaxValue;
        }
    }
}